/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 huliqing, huliqing.cn@gmail.com
 *
 * This file is part of QFaces.
 * QFaces is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QFaces is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QFaces.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 这个文件是QFaces的一部分。
 * 您可以单独使用或分发这个文件，但请不要移除这个头部声明信息.
 * QFaces是一个自由软件，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在QFaces的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看并获取副本。
 *
 * - Author: Huliqing
 * - Contact: huliqing.cn@gmail.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: http://www.huliqing.name/
 */


package name.huliqing.qfaces;

import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 *
 * @author huliqing
 */
public class QFaces {

    private final static Logger logger = Logger.getLogger(QFaces.class.getName());

    private QFaces() {
    }

    /**
     * Get QFaces's resource loader.
     * @return ResLoader2
     */
    public final static ResLoader2 getResLoader2() {
        return ResLoader2.getInstance();
    }

    /**
     * Get QFaces's response.
     * @return Response
     */
    public final static Response getResponse() {
        return Response.getInstance();
    }

    /**
     * Get parameter from the current request.
     * @param key
     * @return value
     */
    public final static String getParam(String key) {
        FacesContext fc = FacesContext.getCurrentInstance();
        if (fc == null) {
            throw new NullPointerException("FacesContext not found!");
        }
        String value = fc.getExternalContext().getRequestParameterMap().get(key);
        return value;
    }

    /**
     * Get attribute from target component(ui), if not found,then return 
     * the defaultValue.
     * @param ui
     * 		Target component
     * @param attrName
     * 		Attribute name
     * @param defaultValue
     * 		The default value will return if attribute not found.
     * @return
     * 		The value of the attribute, if not found,then return defaultValue. 
     */
    public final static Object getAttribute(UIComponent ui, String attrName, Object defaultValue) {
        Object o = ui.getAttributes().get(attrName);
        return o != null ? o : defaultValue;
    }

    /**
     * Convert to Boolean
     * @param val
     * @return Boolean value,if can't convert,then return null.
     */
    public final static Boolean convertToBoolean(Object val) {
        if (val == null || val.equals("")) {
            return null;
        }
        if (val instanceof java.lang.Boolean) {
            return (Boolean) val;
        } else if (val instanceof java.lang.String) {
            return Boolean.valueOf((String) val);
        } else {
            return Boolean.valueOf(val.toString());
        }
    }

    /**
     * Convert to Long
     * @param val
     * @return Long value,if can't convert,then return null.
     */
    public final static Long convertToLong(Object val) {
        if (val == null || val.equals("")) {
            return null;
        }
        if (val instanceof java.lang.Long) {
            return (Long) val;
        } else {
            try {
                if (val instanceof java.lang.String) {
                    return Long.parseLong((String) val);
                } else {
                    return Long.valueOf(val.toString());
                }
            } catch (NumberFormatException nfe) {
                logger.info("Target couldn't convert, val=" + val);
            }
        }
        return null;
    }

    /**
     * Convert to Integer
     * @param val
     * @return Integer value,if can't convert,then return null.
     */
    public final static Integer convertToInteger(Object val) {
        if (val == null || val.equals("")) {
            return null;
        }
        if (val instanceof java.lang.Integer) {
            return (Integer) val;
        } else {
            try {
                if (val instanceof java.lang.String) {
                    return Integer.parseInt((String) val);
                } else {
                    return Integer.valueOf(val.toString());
                }
            } catch (NumberFormatException nfe) {
                logger.info("Target couldn't convert, val=" + val);
            }
        }
        return null;
    }

    public final static Float convertToFloat(Object val) {
        if (val == null || val.equals("")) {
            return null;
        }
        if (val instanceof java.lang.Float) {
            return (Float) val;
        } else {
            try {
                if (val instanceof java.lang.String) {
                    return Float.parseFloat((String) val);
                } else {
                    return Float.valueOf(val.toString());
                }
            } catch (NumberFormatException nfe) {
                logger.info("Target couldn't convert, val=" + val);
            }
        }
        return null;
    }

    // -------------------------------------------------- Expression and Test
    /**
     * Create Value exression
     * @param expression e.g. #{mybean.value}
     * @param returnType e.g. Object.class
     * @return value expression
     */
    public final static ValueExpression createValueExpression(String expression, Class<?> returnType) {
        FacesContext fc = getFacesContext();
        ExpressionFactory ef = fc.getApplication().getExpressionFactory();
        ValueExpression ve = ef.createValueExpression(fc.getELContext(), expression, returnType);
        return ve;
    }

    /**
     * Create method expression.
     * @param expression e.g. #{mybean.action}
     * @param returnType e.g. Object.class
     * @param args e.g. new Class[]{String.class, Date.class}
     * @return method
     */
    public final static MethodExpression createMethodExpression(
            String expression, Class<?> returnType, Class<?>[] args) {
        FacesContext fc = FacesContext.getCurrentInstance();
        if (fc == null) {
            throw new NullPointerException("FacesContext not found!");
        }
        ELContext elc = fc.getELContext();
        ExpressionFactory ef = fc.getApplication().getExpressionFactory();
        return ef.createMethodExpression(elc, expression, returnType, args);
    }

    /**
     * Find children component by id.
     * @param parent
     * @param id
     * @return child component, return null if not found.
     */
    public final static UIComponent findChildComponent(UIComponent parent, String id) {
        UIComponent target = parent.findComponent(id);
        if (target != null) {
            return target;
        }
        List<UIComponent> children = parent.getChildren();
        for (UIComponent child : children) {
            target = findChildComponent(child, id);
            if (target != null) {
                return target;
            }
        }
        return null;
    }

    /**
     * Parse and found viewId from FacesContext
     * @param fc
     * @return viewId
     */
    public final static String getViewId(FacesContext fc) {
        String viewId = null;
        Map<?, ?> requestMap = fc.getExternalContext().getRequestMap();
        viewId = (String) requestMap.get("javax.servlet.include.path_info");
        if (viewId == null) {
            viewId = fc.getExternalContext().getRequestPathInfo();
        }

        if (viewId == null) {
            viewId = (String) requestMap.get("javax.servlet.include.servlet_path");
        }

        if (viewId == null) {
            Object request = fc.getExternalContext().getRequest();
            if (request instanceof HttpServletRequest) {
                viewId = ((HttpServletRequest) request).getServletPath();
            }
        }
        return viewId;
    }

    /**
     * Find HttpSession,create new one if not found.
     * @return HttpSession
     */
    public final static HttpSession getSession() {
        HttpServletRequest request = (HttpServletRequest) getFacesContext().getExternalContext().getRequest();
        HttpSession sess = request.getSession(true);
        return sess;
    }

    /**
     * Get the current FacesContext instance.
     * @return FacesContext
     * @throws NullPointerException
     * 		if FacesContext not found.
     */
    public final static FacesContext getFacesContext() {
        FacesContext fc = FacesContext.getCurrentInstance();
        if (fc == null) {
            throw new NullPointerException("FacesContext not found!");
        }
        return fc;
    }
}
